package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"sync"
	"time"
)

const BUFSIZE = 4096

type Server struct {
	IP   string
	Port int

	OnlineMap map[string]*User
	mapLock   sync.RWMutex

	Message chan string
}

func NewServer(ip string, port int) *Server {
	return &Server{
		IP:        ip,
		Port:      port,
		OnlineMap: make(map[string]*User),
		Message:   make(chan string),
	}
}

func (s *Server) HandleClient(conn net.Conn, user *User, isAlive chan bool) {
	buf := make([]byte, BUFSIZE)

	for {
		n, err := conn.Read(buf)

		// 客户端断开连接
		if n == 0 {
			// s.Broadcast(user, "已下线")
			user.Offline()
			return
		}

		if err != nil && err != io.EOF {
			fmt.Fprintln(os.Stderr, err.Error())
			return
		}

		// 去掉换行符
		msg := string(buf[:n-1])

		// 用户处理消息
		user.DoMessage(msg)

		isAlive <- true
	}
}

// 用户上线-》创建新用户加入到OnlineMap中
// -》channel message广播上线消息到各个客户端的channel
// -》客户端接受到数据
func (s *Server) Handler(conn net.Conn) {
	user := NewUser(conn, s)
	user.Online()

	// 判断用户是否活跃
	isAlive := make(chan bool)

	// 接收客户端发送的消息
	go s.HandleClient(conn, user, isAlive)
	select {
	case <-isAlive:
		// 下面代码会重置超时时间
	case <-time.After(time.Second * 600):
		user.SendMsg("你被踢了")
		close(user.C)
		conn.Close()
		return
	}
}

// 把用户上线的消息，发送到服务器的message通道
func (s *Server) Broadcast(user *User, str string) {
	msg := fmt.Sprintf("[%s] %s:%s", user.Addr, user.Name, str)
	s.Message <- msg
}

// 从服务器的message通道获取消息，广播到上线客户端
func (s *Server) ListenMessager() {
	for {
		msg := <-s.Message

		s.mapLock.Lock()
		for _, user := range s.OnlineMap {
			user.C <- msg
		}
		s.mapLock.Unlock()
	}
}

func (s *Server) Start() {
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.IP, s.Port))
	if err != nil {
		log.Fatalln(err)
	}
	defer listener.Close()

	// 看Message通道中是否有内容，广播给上线的用户
	go s.ListenMessager()

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			continue
		}

		go s.Handler(conn)
	}
}

func main() {
	server := NewServer("127.0.0.1", 8000)
	server.Start()
}
